﻿#light

module Dwarf_Managed

open System
open System.Collections.Generic
open System.Runtime.InteropServices
open MPI
open System.Threading

/// <summary>
/// Write the rules of command line structure.
/// </summary>
[<DllImport(@"CliTools.dll")>]
extern void usage();

let ROOT_PROCESS = 0

let getSettings(args : String[]) =
    if Communicator.world.Rank = ROOT_PROCESS then
        Dwarf_Managed_Common.Init(args) //Parse all arguments for dwarf.

    //Distribute size of matrices.
    MPI.Communicator.world.Broadcast(ref Dwarf_Managed_Common.msize, ROOT_PROCESS)

    //Init matrices.
    if Communicator.world.Rank <> ROOT_PROCESS then
        Dwarf_Managed_Common.rgrid <- Array2D.zeroCreate<double> Dwarf_Managed_Common.msize Dwarf_Managed_Common.msize
      
        Dwarf_Managed_Common.lgrid <- Array2D.zeroCreate<double> 1 Dwarf_Managed_Common.msize

        Dwarf_Managed_Common.result <- Array2D.zeroCreate<double> 1 Dwarf_Managed_Common.msize

    //Distribute right matrix to all.
    for i = 0 to Dwarf_Managed_Common.msize - 1 do
        for j = 0 to Dwarf_Managed_Common.msize - 1 do
            MPI.Communicator.world.Broadcast(ref Dwarf_Managed_Common.rgrid.[i,j], ROOT_PROCESS)
        done
    done
    
let getTranspose(matrix : double[,], n : int) : double[,] = 
    let mutable transpose = Array2D.zeroCreate<double> n n
    for i = 0 to n - 1 do
        transpose.[i,i] <- matrix.[i,i]
        for j = i + 1 to n - 1 do
            transpose.[i,j] <- matrix.[j,i]
            transpose.[j,i] <- matrix.[i,j]
            
    transpose

let Solve() =
    let rtransposed = getTranspose(Dwarf_Managed_Common.rgrid, Dwarf_Managed_Common.msize)

    for i = 0 to Dwarf_Managed_Common.msize - 1 do
        for j = 0 to Dwarf_Managed_Common.msize - 1 do
            let mutable cell = 0.0
            for k = 0 to Dwarf_Managed_Common.msize - 1 do 
                cell <- cell + Dwarf_Managed_Common.lgrid.[i,k] * rtransposed.[j,k]
            Dwarf_Managed_Common.result.[i,j] <- cell    
 
let main() =   
    
    try 
        let args = System.Environment.GetCommandLineArgs()
        let env = new MPI.Environment(ref args)             // MPI Initialization.
        if Communicator.world.Size = 1 then
            raise (new Exception("Only one mpi process."))

        getSettings(args)                                   // Get settings from the command line.

        Communicator.world.Barrier()
        if Communicator.world.Rank = ROOT_PROCESS then
            Dwarf_Managed_Common.Start()                    // Start new time count.
        Solve()                                             // Solve the current problem.
        Communicator.world.Barrier()
        if Communicator.world.Rank = ROOT_PROCESS then
            Dwarf_Managed_Common.Finish()                   // Stop the time count and write results.
            
        env.Dispose()
    with e -> Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); usage()
         
main()
